﻿using MicroMVVM.Interfaces;
using Windows.ApplicationModel;
using Windows.ApplicationModel.DataTransfer;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace MicroMVVM
{
    /// <summary>
    /// This class represents the dependency property to be used views, which sets the view model identifier.
    /// </summary>
    public class ViewModelLocator
    {
        private static TypedEventHandler<DataTransferManager, DataRequestedEventArgs> _handler;

        private static DataTransferManager _dataTransferManager;

        #region Model

        /// <summary>
        /// Model Attached Dependency Property
        /// </summary>
        public static readonly DependencyProperty ModelProperty =
            DependencyProperty.RegisterAttached("Model", typeof (object), typeof (ViewModelLocator),
                                                new PropertyMetadata(false, OnModelChanged));

        /// <summary>
        /// Gets the Model property. This dependency property 
        /// indicates the View Model.
        /// </summary>
        public static object GetModel(DependencyObject d)
        {
            return d.GetValue(ModelProperty);
        }

        /// <summary>
        /// Sets the Model property. This dependency property 
        /// indicates View Model.
        /// </summary>
        public static void SetModel(DependencyObject d, object value)
        {
            d.SetValue(ModelProperty, value);
        }

        /// <summary>
        /// Handles changes to the Model property.
        /// </summary>
        private static void OnModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var identifier = d.GetValue(ModelProperty) as string;

            var control = d as Control;

            if ((control == null) || (identifier == null)) return;

            var viewModel = Container.ResolveViewModel(identifier, DesignMode.DesignModeEnabled);

            if (viewModel == null) return;

            control.DataContext = viewModel;

            System.Diagnostics.Debug.WriteLine(string.Format("Attaching ViewModel {0} with View {1}.", viewModel, control));

            InitialiseViewAware(control);

            InitialiseDesignAware(control, identifier);

            InitialiseShareableContent(viewModel);
        }

        private static void InitialiseViewAware(Control page)
        {
            if (DesignMode.DesignModeEnabled) return;

            var viewAware = Container.ResolveService<IViewAware>(DesignMode.DesignModeEnabled);

            if (viewAware != null) viewAware.Current = page;
        }

        private static void InitialiseDesignAware(Control page, string identifier)
        {
            if (DesignMode.DesignModeEnabled == false) return;

            object viewModel;

            page.Resources.TryGetValue(identifier, out viewModel);

            if (viewModel == null) return;

            page.DataContext = viewModel;

            var designtimeAwareViewModel = viewModel as IDesigntimeAware;

            if (designtimeAwareViewModel != null) designtimeAwareViewModel.DesigntimeAware();
        }

        private static void InitialiseShareableContent(object viewModel)
        {
            if (DesignMode.DesignModeEnabled) return;

            var shareableContentViewModel = viewModel as IShareableContent;

            if (_dataTransferManager != null)
            {
                _dataTransferManager.DataRequested -= _handler;

                _dataTransferManager = null;
            }

            _dataTransferManager = DataTransferManager.GetForCurrentView();

            if (shareableContentViewModel == null)
                _handler = (sender, args) => args.Request.FailWithDisplayText(" ");
            else
                _handler = shareableContentViewModel.SetShareableContent;

            _dataTransferManager.DataRequested += _handler;
        }

        #endregion
    }
}